#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Webhook客户端工具
用于向被测程序发送webhook回调
"""

import requests
import hashlib
import time
import random
import string
import base64
import struct
from datetime import datetime
from Crypto.Cipher import AES
from utils.logger import get_logger

logger = get_logger(__name__)


class WebhookClient:
    """Webhook客户端"""
    
    def __init__(self, webhook_url, token, encoding_aes_key, corp_id="wxc4c1ad1d26dc0daf"):
        """
        初始化Webhook客户端
        
        Args:
            webhook_url: webhook回调地址
            token: 微信Token
            encoding_aes_key: 微信EncodingAESKey
            corp_id: 企业ID
        """
        self.webhook_url = webhook_url
        self.token = token
        self.encoding_aes_key = encoding_aes_key
        self.corp_id = corp_id
        # 解码AES密钥
        self.key = base64.b64decode(self.encoding_aes_key + "=")
        
    def pkcs7_pad_bytes(self, data: bytes, block_size: int = 16) -> bytes:
        """PKCS#7字节级补位 - 参考demo实现"""
        pad_len = block_size - (len(data) % block_size)
        return data + bytes([pad_len]) * pad_len
        
    def generate_echostr(self):
        """生成符合企业微信规范的echostr - 参考demo实现"""
        # 1. 生成16字节的随机字符串
        random_str = ''.join(random.choices(string.ascii_letters + string.digits, k=16)).encode('utf-8')
        
        # 2. 生成一个简单的echostr文本
        echostr_text = "mock_echostr_123"
        
        # 3. 消息长度（4字节，使用大端序）
        msg_len = struct.pack('>I', len(echostr_text))
        
        # 4. 拼接：random(16字节) + msg_len(4字节) + echostr_text + receive_id
        content = random_str + msg_len + echostr_text.encode('utf-8') + self.corp_id.encode('utf-8')
        
        # 5. PKCS#7字节级补位
        padded = self.pkcs7_pad_bytes(content, 16)
        
        # 6. AES-CBC加密
        cipher = AES.new(self.key, AES.MODE_CBC, self.key[:16])
        encrypted = cipher.encrypt(padded)
        
        return base64.b64encode(encrypted).decode()
    
    def verify_signature(self, msg_signature, timestamp, nonce, echostr):
        """验证签名"""
        # 1. 将token、timestamp、nonce、echostr四个参数进行字典序排序
        signature_list = [self.token, timestamp, nonce, echostr]
        signature_list.sort()
        
        # 2. 将四个参数拼接成一个字符串进行sha1加密
        signature_str = ''.join(signature_list)
        calculated_signature = hashlib.sha1(signature_str.encode()).hexdigest()
        
        # 3. 开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
        return calculated_signature == msg_signature
    
    def encrypt_message(self, xml_content):
        """加密消息 - 参考demo实现"""
        # 1. 生成16字节的随机字符串
        random_str = ''.join(random.choices(string.ascii_letters + string.digits, k=16)).encode('utf-8')
        
        # 2. 消息长度（4字节，使用大端序）- 按字节长度
        xml_bytes = xml_content.encode('utf-8')
        msg_len = struct.pack('>I', len(xml_bytes))
        
        # 3. 拼接：random(16字节) + msg_len(4字节) + xml_content + receive_id
        content = random_str + msg_len + xml_bytes + self.corp_id.encode('utf-8')
        
        # 4. PKCS#7字节级补位
        padded = self.pkcs7_pad_bytes(content, 16)
        
        # 5. AES-CBC加密
        cipher = AES.new(self.key, AES.MODE_CBC, self.key[:16])
        encrypted = cipher.encrypt(padded)
        
        encrypted_msg = base64.b64encode(encrypted).decode()
        logger.info(f"消息加密完成，XML长度: {len(xml_content)}字符")
        
        return encrypted_msg
    
    def generate_signature(self, timestamp, nonce, echostr=None):
        """
        生成微信签名
        
        Args:
            timestamp: 时间戳
            nonce: 随机数
            echostr: 加密字符串（可选）
            
        Returns:
            签名字符串
        """
        # 按字典序排序
        params = [self.token, timestamp, nonce]
        if echostr:
            params.append(echostr)
        
        # 拼接字符串
        string_to_sign = ''.join(sorted(params))
        
        # SHA1加密
        signature = hashlib.sha1(string_to_sign.encode('utf-8')).hexdigest()
        
        return signature
    
    def generate_nonce(self, length=16):
        """生成随机字符串"""
        return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
    
    def create_xml_message(self, msg_type, content, from_user, to_user, msg_id=None):
        """
        创建XML格式的客服事件消息（符合真实企业微信格式）
        
        Args:
            msg_type: 消息类型（将被忽略，统一使用event）
            content: 消息内容（将被忽略，统一使用客服事件）
            from_user: 发送者
            to_user: 接收者
            msg_id: 消息ID
            
        Returns:
            XML字符串
        """
        timestamp = int(datetime.now().timestamp())
        if not msg_id:
            msg_id = f"msg_{int(time.time())}"
        
        # 确保所有字符串都是UTF-8编码
        to_user = str(to_user).encode('utf-8').decode('utf-8')
        from_user = str(from_user).encode('utf-8').decode('utf-8')
        
        # 按照真实企业微信格式创建客服事件消息
        xml_template = f"""<xml>
<ToUserName><![CDATA[{to_user}]]></ToUserName>
<FromUserName><![CDATA[{from_user}]]></FromUserName>
<CreateTime>{timestamp}</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[kf_msg_or_event]]></Event>
<Token><![CDATA[mock_token_{msg_id}]]></Token>
<OpenKfId><![CDATA[{self.corp_id}]]></OpenKfId>
</xml>"""
        
        return xml_template
    
    def send_webhook(self, msg_type, content, from_user, to_user="gh_test", msg_id=None):
        """
        发送webhook回调
        
        Args:
            msg_type: 消息类型
            content: 消息内容
            from_user: 发送者（客户ID）
            to_user: 接收者（公众号ID）
            msg_id: 消息ID
            
        Returns:
            响应结果
        """
        try:
            # 生成参数
            timestamp = str(int(datetime.now().timestamp()))
            nonce = self.generate_nonce()
            
            # 创建XML消息
            xml_data = self.create_xml_message(msg_type, content, from_user, to_user, msg_id)
            
            # 加密XML消息
            encrypted_xml = self.encrypt_message(xml_data)
            
            # 生成签名（使用加密后的消息体）
            signature = self.generate_signature(timestamp, nonce, encrypted_xml)
            
            # 构建URL参数
            params = {
                'msg_signature': signature,
                'timestamp': timestamp,
                'nonce': nonce
            }
            
            # 构造XML请求体（参考demo格式）
            # 确保to_user也是UTF-8编码
            to_user_encoded = str(to_user).encode('utf-8').decode('utf-8')
            request_xml = f"""<xml>
<ToUserName><![CDATA[{to_user_encoded}]]></ToUserName>
<Encrypt><![CDATA[{encrypted_xml}]]></Encrypt>
</xml>"""
            
            # 发送请求
            headers = {
                'Content-Type': 'application/xml'
            }
            
            logger.info(f"发送webhook回调 - URL: {self.webhook_url}, 用户: {from_user}, 类型: {msg_type}")
            
            response = requests.post(
                self.webhook_url,
                params=params,
                data=request_xml,
                headers=headers,
                timeout=10
            )
            
            logger.info(f"Webhook响应 - 状态码: {response.status_code}")
            
            return {
                'success': response.status_code == 200,
                'status_code': response.status_code,
                'response': response.text,
                'xml_data': xml_data,
                'encrypted_xml': encrypted_xml,
                'request_xml': request_xml
            }
            
        except Exception as e:
            logger.error(f"发送webhook失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'xml_data': xml_data if 'xml_data' in locals() else None,
                'encrypted_xml': encrypted_xml if 'encrypted_xml' in locals() else None,
                'request_xml': request_xml if 'request_xml' in locals() else None
            }
    
    def verify_webhook_url(self, echostr=None):
        """
        验证webhook URL
        
        Args:
            echostr: 明文字符串（可选，如果不提供则使用默认值）
            
        Returns:
            验证结果
        """
        try:
            timestamp = str(int(datetime.now().timestamp()))
            nonce = self.generate_nonce()
            
            # 如果没有提供echostr，则使用默认值
            if not echostr:
                echostr = "mock_echostr_123"
            
            # 生成加密的echostr（参考demo）
            encrypted_echostr = self.generate_echostr()
            
            # 生成签名（使用加密后的echostr）
            signature = self.generate_signature(timestamp, nonce, encrypted_echostr)
            
            # 构建URL参数
            params = {
                'msg_signature': signature,
                'timestamp': timestamp,
                'nonce': nonce,
                'echostr': encrypted_echostr
            }
            
            logger.info(f"验证webhook URL - URL: {self.webhook_url}")
            
            response = requests.get(
                self.webhook_url,
                params=params,
                timeout=10
            )
            
            logger.info(f"URL验证响应 - 状态码: {response.status_code}")
            
            return {
                'success': response.status_code == 200 and response.text == "mock_echostr_123",
                'status_code': response.status_code,
                'response': response.text,
                'params': params
            }
            
        except Exception as e:
            logger.error(f"验证webhook URL失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }
